package cn.darkhorse.device.service.impl;

import cn.darkhorse.device.iot.constant.IotConstant;
import cn.darkhorse.device.pojo.IotPointTable;
import cn.darkhorse.device.mapper.IotPointTableMapper;
import cn.darkhorse.device.service.IotPointTableService;
import cn.darkhorse.device.vo.ExtraInfoVO;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import lombok.Data;
import net.sourceforge.jeval.EvaluationException;
import net.sourceforge.jeval.Evaluator;
import org.springframework.stereotype.Service;
import org.springframework.util.NumberUtils;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yuanjun
 * @since 2023-10-11
 */
@Service
public class IotPointTableServiceImpl extends ServiceImpl<IotPointTableMapper, IotPointTable> implements IotPointTableService {


    private static final Evaluator evaluator = new Evaluator();
    @Override
    public Object buildValue(IotPointTable iotPointTable, Object value) {
        if (iotPointTable.getInputType()!=null){
            if (iotPointTable.getInputType() == 1 || iotPointTable.getInputType() == 2) {
                value = convertToDecimal(value, iotPointTable.getInputType() == 1? 2:16);
            }else if (iotPointTable.getInputType() == 3) {
                //TODO 待实现 ASCII码转换
            }
        }
        if (StringUtils.isNotEmpty(iotPointTable.getDataFormula())){
//            BigDecimal val = performOperation(iotPointTable.getDataFormula(), value);
            Object val = calculateFormula(iotPointTable.getDataFormula(), value);
            if (val != null){
                value =  new BigDecimal(val.toString()).setScale(iotPointTable.getScale(), RoundingMode.HALF_UP);
            }
        }
        if (iotPointTable.getInputType()!=null){
            if (iotPointTable.getInputType() == 4) {
//          处理风向传入的值,可以先做转换再进行计算
                double degree = NumberUtils.parseNumber(value.toString(), Double.class);
                degree = degree % 360;

                String[] directions = {
                        "北", "北东北", "东北", "东东北", "东", "东东南", "东南", "南东南",
                        "南", "南西南", "西南", "西西南", "西", "西西北", "西北", "北西北"
                };
                // 计算索引  增加偏移值,确保如当输入为0时，能够正确对应到“北”这个方向
                int index = (int) Math.floor((degree + 11.25) / 22.5);

                value = directions[index % 16];
            }
        }
        return value;
    }

    /**
     * 翻译值 带单位
     * @param pointTable
     * @param sourceValue
     * @return
     */
    public String translateValue(IotPointTable pointTable, String sourceValue) {
        sourceValue = convertByPattern(sourceValue);
        String value = sourceValue;
        Map<String, String> extraInfo = getExtraInfo(pointTable.getExtraJson());

        if (extraInfo == null) {
            return value;
        }

        // 根据点表类型翻译value，如果设置了单位，还要加上单位
        if (IotConstant.POINT_TYPE_BOOLEAN.equals(pointTable.getDataType())) {
            // 布尔型
            value = extraInfo.get(sourceValue) == null ? sourceValue : extraInfo.get(sourceValue);
        }

        if (IotConstant.POINT_TYPE_NUMBER.equals(pointTable.getDataType())) {
            // 数值型
            value = extraInfo.get("unit") == null ? sourceValue : sourceValue + " " + extraInfo.get("unit")  ;
        }

        if (IotConstant.POINT_TYPE_STRING.equals(pointTable.getDataType())) {
            // 字符型
            value = sourceValue ;
        }

        if (IotConstant.POINT_TYPE_ENUM.equals(pointTable.getDataType())) {
            // 枚举型


            value =  extraInfo.get(sourceValue) == null ? value : extraInfo.get(sourceValue);

        }
        return value;
    }

    /**
     * 翻译值 单位与值分开返回
     * @param pointTable
     * @param sourceValue
     * @return
     */
    @Override
    public ExtraInfoVO translateValue2(IotPointTable pointTable, String sourceValue) {

        ExtraInfoVO extraInfoVO = new ExtraInfoVO();

        sourceValue = convertByPattern(sourceValue);
        String value = sourceValue;
        Map<String, String> extraInfo = getExtraInfo(pointTable.getExtraJson());

        if (extraInfo == null) {
            extraInfoVO.setValue(value);
            return extraInfoVO;
        }

        // 根据点表类型翻译value，如果设置了单位，还要加上单位
        if (IotConstant.POINT_TYPE_BOOLEAN.equals(pointTable.getDataType())) {
            // 布尔型
            value = extraInfo.get(sourceValue) == null ? sourceValue : extraInfo.get(sourceValue);
        }

        if (IotConstant.POINT_TYPE_NUMBER.equals(pointTable.getDataType())) {
            // 数值型
            extraInfoVO.setUnit(extraInfo.get("unit") );
        }

        if (IotConstant.POINT_TYPE_STRING.equals(pointTable.getDataType())) {
            // 字符型
            value = sourceValue ;
        }

        if (IotConstant.POINT_TYPE_ENUM.equals(pointTable.getDataType())) {
            // 枚举型


            value =  extraInfo.get(sourceValue) == null ? value : extraInfo.get(sourceValue);

        }
        extraInfoVO.setValue(value);
        if (extraInfoVO.getUnit() == null){
            extraInfoVO.setUnit("");
        }
        return extraInfoVO;
    }

    /**
     * 去掉给定字符串（小数）后面的无效0
     *
     * @param value 小数的字符串表示
     * @return 如果转换失败，返回null
     */
    private String convertByPattern(String value) {

        String regex = "^(-?\\d*)(\\.?0*)$";
        Matcher matcher = Pattern.compile(regex).matcher(value);
        if (matcher.find()) {
            return matcher.group(1);
        }
        String regex1 = "^(-?\\d*\\.\\d*[1-9])(0*)$";
        Matcher matcher1 = Pattern.compile(regex1).matcher(value);
        if (matcher1.find()) {
            return matcher1.group(1);
        }
        return value;
    }
    /**
     * 点表中的扩展信息，转换为一个map对象
     * @param extraJson
     * @return
     */
    private Map<String, String> getExtraInfo(String extraJson) {
//        List<JSONObject> result = new ArrayList<>();
        if (StringUtils.isEmpty(extraJson)) {
            return null;
        }
        JSONArray jsonArray = JSONArray.parse(extraJson);

        Map<String, String> collect = new HashMap<>();
        for (int i = 0; i < jsonArray.size(); i++) {
            JSONObject o = (JSONObject) jsonArray.get(i);
            collect.put(o.get("label").toString(), o.get("value").toString());
        }
        return collect;
    }

    /**
     * 根据输入的运算符字符串和数值，执行相应的数学运算。
     *
     * @param operation 运算符字符串，如 "/10"
     * @param number    需要进行运算的数值，应为数值
     * @return 运算结果
     */
//    弃用
    public BigDecimal performOperation(String operation, Object number) {
        if (!NumberUtil.isNumber( String.valueOf(number))){
            return  null;
        }
        String operator = operation.substring(0, 1);
        String operandStr = operation.substring(1);
        BigDecimal operand = new BigDecimal(operandStr);
        BigDecimal value = new BigDecimal(number.toString());

        switch (operator) {
            case "+":
                return value.add(operand);
            case "-":
                return value.subtract(operand);
            case "*":
                return value.multiply(operand);
            case "/":
                // 防止除以零错误
                if (operand.compareTo(BigDecimal.ZERO) == 0) {
                    throw new IllegalArgumentException("Cannot divide by zero.");
                }
                return value.divide(operand, 4, RoundingMode.HALF_UP);
            default:
                return null;
        }
    }

    /**
     * 替换公式中的通配符并计算结果。
     * 公式的格式为 "x+#+y" 只对第一个通配符做处理
     * @param formula 包含通配符的数学公式字符串。
     * @param wildcardValue 用于替换通配符的数值。
     * @return 计算后的结果。
     */
    public Object calculateFormula(String formula, Object wildcardValue) {
        // 明确使用JavaScript引擎，并替换通配符
        formula = formula.replaceFirst("#", String.valueOf(wildcardValue)); // 匹配通配符
        System.out.println(formula);
        try {
            return evaluator.evaluate(formula);
        }  catch (EvaluationException e) {
            return null;
        }
    }

    /**
     * 将指定进制的数值字符串转换为十进制整数。
     *
     * @param value 需要转换的数值字符串。
     * @param base 输入进制
     * @return 转换后的十进制整数。
     * @throws IllegalArgumentException 如果base不在2到36之间，或者value包含非有效字符。
     */
    public Object convertToDecimal(Object value, int base) {
            String str = String.valueOf(value);
            int result = 0;
            for (int i = 0; i < str.length(); i++) {
                char c = str.charAt(i);
                int digitValue = Character.digit(c, base);
                if (digitValue == -1) {
                    return value;
                }
                result = result * base + digitValue;
            }
            return result;

    }
}
